﻿namespace Core.DataAccess.ApiJson
{
    using Core.DataAccess.ApiJson.Controllers;
    using Core.DataAccess.ApiJson.SearchService;
    using Core.Framework;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using SqlSugar;
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Web;

    public class ApiJsonController
    {

        private readonly SelectTable selectTable;
        private readonly SqlSugarClient sqlSugarClient;
        private readonly ISearchProvider searchProvider; // == null 就说明 没有启用 es
        private Dictionary<string, TableSchema> databaseSchema;

        public ApiJsonController(SelectTable _selectTable, ISearchProvider searchProvider)
        {
            this.searchProvider = searchProvider;
            selectTable = _selectTable;
            this.sqlSugarClient = _selectTable.GetSqlSugarClient();
        }


        public void SetTableSchema(Dictionary<string, TableSchema> schema)
        {
            this.databaseSchema = schema;
        }

        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public JObject Query(string json)
        {
            return this.selectTable.Query(json);
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public JObject Add(string json, out object trigger, out long id)
        {
            id = 0;
            trigger = null;
            json = HttpUtility.UrlDecode(json);
            JObject ht = new JObject();
            ht.Add("code", 200);
            ht.Add("info", "success");
            try
            {
                JObject jobject = JObject.Parse(json);

                foreach (var item in jobject)
                {
                    string table = item.Key.Trim();
                    TableSchema tableSchema = this.databaseSchema.Where(a => a.Key == table).Select(a => a.Value).FirstOrDefault();

                    var dt = JsonConvert.DeserializeObject<Dictionary<string, object>>(item.Value.ToString());

                    if (dt.ContainsKey("@trigger"))
                    {
                        dt.Remove("@trigger", out trigger);
                    }

                    id = this.sqlSugarClient.Insertable(dt).AS(table).ExecuteReturnIdentity();

                    if (id > 0 && tableSchema != null && tableSchema?.SearchIndex?.Count > 0 && this.searchProvider != null)
                    {
                        // 添加索引
                        this.searchProvider.AddIndexData(table, new IndexData
                        {
                            Key = id.ToString(),
                            Data = this.GetIndexData(dt, tableSchema)
                        });
                    }

                    ht.Add(table, JToken.FromObject(new { code = 200, info = "success", date = id }));
                }
            }
            catch (Exception ex)
            {
                ht["code"] = 500;
                ht["info"] = ex.Message;
            }

            return ht;
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public JObject Edit(string json)
        {
            json = HttpUtility.UrlDecode(json);
            JObject ht = new JObject();
            ht.Add("code", 200);
            ht.Add("info", "success");
            try
            {
                JObject jobject = JObject.Parse(json);

                foreach (var item in jobject)
                {
                    string table = item.Key.Trim();
                    TableSchema tableSchema = this.databaseSchema.Where(a => a.Key == table).Select(a => a.Value).FirstOrDefault();

                    var sb = new System.Text.StringBuilder(100);

                    sb.Append($"  update [{table}] set ");

                    var primarykey = selectTable.GetPrimarykeyColName(table);

                    var value = JObject.Parse(item.Value.ToString());

                    var p = new List<SugarParameter>();

                    List<string> rows = new List<string>();

                    foreach (var f in value)
                    {
                        if (f.Key == primarykey)
                            continue;
                        rows.Add(f.Key);
                        p.Add(new SugarParameter($"@{f.Key}", f.Value.ToString()));
                    }

                    sb.Append($" {string.Join(",", rows.Select(a => $"{a}=@{a}"))} where ");

                    if (!value.ContainsKey(primarykey))
                    {
                        ht["code"] = 500;
                        ht["msg"] = "未传主键id";
                        break;
                    }
                    else
                    {
                        sb.Append($" {primarykey}=@id ");
                        p.Add(new SugarParameter($"@id", value[primarykey]));
                    }

                    int row = this.sqlSugarClient.Ado.ExecuteCommand(sb.ToString(), p);

                    if (row > 0 && tableSchema != null && tableSchema?.SearchIndex?.Count > 0 && this.searchProvider != null)
                    {
                        // 更新索引
                        List<string> list = new List<string>();
                        foreach (var index in tableSchema?.SearchIndex)
                        {
                            foreach (var indexValue in index.Value)
                            {
                                if (!list.Contains(indexValue))
                                {
                                    list.Add($"[{indexValue}]");
                                }
                            }
                        }
                        var reader = this.sqlSugarClient.Ado.GetDataReader($"select top 1 {string.Join(',', list)} from [{table}] where [{primarykey}] = '{value[primarykey]}'");
                        this.searchProvider.ModifyIndexData(table, new IndexData
                        {
                            Key = value[primarykey].ToString(),
                            Data = this.GetIndexData(reader, tableSchema)
                        });
                    }

                    ht.Add(table, JToken.FromObject(new { code = 200, info = "success", date = row }));
                }
            }
            catch (Exception ex)
            {

                ht["code"] = 500;
                ht["info"] = ex.Message;
            }
            return ht;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public JObject Remove(string json)
        {
            json = HttpUtility.UrlDecode(json);
            JObject ht = new JObject();
            ht.Add("code", 200);
            ht.Add("info", "success");
            try
            {
                JObject jobject = JObject.Parse(json);
                foreach (var item in jobject)
                {
                    int row = 0;
                    List<string> list = new List<string>();
                    string table = item.Key.Trim();
                    var primarykey = selectTable.GetPrimarykeyColName(table);
                    var value = JObject.Parse(item.Value.ToString());
                    var sb1 = new System.Text.StringBuilder(100);
                    var sb2 = new System.Text.StringBuilder(100);


                    sb1.Append($"select [{primarykey}] FROM {table} where");
                    var p1 = new List<SugarParameter>();
                    foreach (var f in value)
                    {
                        string lastChar = ((JProperty)value.Last).Name == f.Key ? string.Empty : "and";
                        sb1.Append($" {f.Key} = @{f.Key} {lastChar} ");
                        p1.Add(new SugarParameter($"@{f.Key}", f.Value.ToString()));
                    }
                    var reader = this.sqlSugarClient.Ado.GetDataReader(sb1.ToString(), p1);
                    while (reader.Read())
                    {
                        list.Add(reader[primarykey].ToString());
                    }

                    if (list.Count > 0)
                    {
                        sb2.Append($"delete FROM [{table}] where [{primarykey}] in ({string.Join(',', list.Select(a => $"'{a}'"))})");
                        row = this.sqlSugarClient.Ado.ExecuteCommand(sb2.ToString());
                    }


                    TableSchema tableSchema = this.databaseSchema.Where(a => a.Key == table).Select(a => a.Value).FirstOrDefault();
                    // 删除索引
                    if (row > 0 && tableSchema != null && tableSchema?.SearchIndex?.Count > 0 && this.searchProvider != null)
                    {
                        foreach (var indexDataKey in list)
                        {
                            this.searchProvider.DeleteIndexData(table, indexDataKey);
                        }
                    }


                    ht.Add(table, JToken.FromObject(new { code = 200, info = "success", date = row }));

                }
            }
            catch (Exception ex)
            {

                ht["code"] = 500;
                ht["info"] = ex.Message;
            }
            return ht;
        }

        private object GetIndexData(Dictionary<string, object> dic, TableSchema tableSchema)
        {
            var indexSchema = tableSchema.SearchIndex;

            Dictionary<string, object> data = new Dictionary<string, object>();

            foreach (var item in indexSchema)
            {
                bool isText = item.Value.Count > 1;
                object value = null;
                string field = item.Value[0];

                if (isText)
                {
                    value = string.Join(',', item.Value.Select(a => dic[a]).Where(a => a != null));
                }
                else if (item.Value.Count == 1)
                {
                    if (tableSchema.Columns.ContainsKey(field))
                    {
                        switch (tableSchema.Columns[field].Type)
                        {
                            case ColumnType.number:
                            case ColumnType.@decimal:
                            case ColumnType.@float:
                                value = dic[field];
                                break;

                            case ColumnType.date:
                                value = Convert.ToDateTime(dic[field] ?? "1994/03/12 00:00:00");
                                break;

                            case ColumnType.location:
                                var locationstring = dic[field].ToString();
                                if (!string.IsNullOrWhiteSpace(locationstring))
                                {
                                    value = locationstring.TryToEntity<Location>();
                                }
                                break;

                            case ColumnType.@bool:
                                value = Convert.ToBoolean(dic[field] ?? "False");
                                break;

                            case ColumnType.text:
                            case ColumnType.@char:
                            default:
                                value = dic[field].ToString();
                                break;
                        }
                    }
                }

                if (value != null)
                {
                    data.Add(item.Key, value);
                }
                else if (tableSchema.Columns[field].Type == ColumnType.location)
                {
                    // 俄罗斯地址
                    data.Add(item.Key, new Location { lat = 73.51156F, lon = 100.942979F });
                }
            }

            return data;
        }

        private object GetIndexData(IDataReader dic, TableSchema tableSchema)
        {
            var indexSchema = tableSchema.SearchIndex;

            Dictionary<string, object> data = new Dictionary<string, object>();

            foreach (var item in indexSchema)
            {
                bool isText = item.Value.Count > 1;
                object value = null;
                string field = item.Value[0];

                if (isText)
                {
                    value = string.Join(',', item.Value.Select(a => dic[a]).Where(a => a != null));
                }
                else if (item.Value.Count == 1)
                {
                    if (tableSchema.Columns.ContainsKey(field))
                    {
                        switch (tableSchema.Columns[field].Type)
                        {
                            case ColumnType.number:
                            case ColumnType.@decimal:
                            case ColumnType.@float:
                                value = dic[field];
                                break;

                            case ColumnType.date:
                                value = Convert.ToDateTime(dic[field] ?? "1994/03/12 00:00:00");
                                break;

                            case ColumnType.location:
                                var locationstring = dic[field].ToString();
                                if (!string.IsNullOrWhiteSpace(locationstring))
                                {
                                    value = locationstring.TryToEntity<Location>();
                                }
                                break;

                            case ColumnType.@bool:
                                value = Convert.ToBoolean(dic[field] ?? "False");
                                break;

                            case ColumnType.text:
                            case ColumnType.@char:
                            default:
                                value = dic[field].ToString();
                                break;
                        }
                    }
                }

                if (value != null)
                {
                    data.Add(item.Key, value);
                }
                else if (tableSchema.Columns[field].Type == ColumnType.location)
                {
                    // 俄罗斯地址
                    data.Add(item.Key, new Location { lat = 73.51156F, lon = 100.942979F });
                }
            }

            return data;
        }

    }
}